﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Transactions;
using DevFramework.Core.Aspects.AuthorizationAspects;
using DevFramework.Core.Aspects.CacheAspects;
using DevFramework.Core.Aspects.LogAspects;
using DevFramework.Core.Aspects.PerformanceAspects;
using DevFramework.Core.Aspects.TransactionAspects;
using DevFramework.Core.Aspects.ValidationAspects;
using DevFramework.Core.CrossCuttingConcern.ExceptionHandling.Exceptions;
using DevFramework.Core.CrossCuttingConcern.Logging.Log4Net.Loggers;
using DevFramework.Core.CrossCuttingConcern.Transaction.ManageHelper;
using DevFramework.Core.Utilities.Search;
using DevFramework.Business.Abstract;
using DevFramework.Business.Specs.ProductSpecs;
using DevFramework.Business.ValidationRules.FluentValidation;
using DevFramework.DataLayer.Abstract;
using DevFramework.Entities.Concrete;
using DevFramework.Entities.ComplexType;
using DevFramework.Entities.Concrete;

namespace DevFramework.Business.Concrete.Managers
{
    
    public class ProductManager : ManagerBase, IProductService
    {
        private readonly IProductDal _productDal;
        private readonly ICategoryDal _categoryDal;

        public ProductManager(IProductDal productDal, ICategoryDal categoryDal)
        {
            _productDal = productDal;
            _categoryDal = categoryDal;
        }
        [CacheAspect]
        public List<Product> GetAll()
        {
            return _productDal.GetList();
        }
        [CacheAspect]
        public Product Get(int id)
        {
            return _productDal.Get(t => t.ProductId == id);
        }


        [CacheAspect(300)]
        [LogAspect(typeof(DataBaseLoggerService))]
        [LogAspect(typeof(EventLoggerService))]
        public List<Product> GetByCategory(int categoryId)
        {
            return _productDal.GetList(filter: t => t.CategoryId == categoryId).ToList();
        }

        [FluentValidationAspect(typeof(ProductValidator))]
        [CacheRemoveAspect]
        public Product Add(Product product)
        {
           
            //IsSatisfiedBy method returns true or false. 
            //If It is false that means we have a business exception in BusinessRules.BusinessExceptions list
            if (ProductSpecs.ProductMustBeInBeverageCategory.
                Or(ProductSpecs.ProductMustBeInCondimentsCategory).And(ProductSpecs.ProductNameMustBeUnique).
                IsSatisfiedBy(product))
            {
                return _productDal.Add(product);
            }

            foreach (var businessException in BusinessRules.BusinessExceptions)
            {
                throw businessException;
            }

            return product;
        }

        public void Update(Product product)
        {
            _productDal.Update(product);
        }

        public void Delete(Product product)
        {
            _productDal.Delete(product);
        }

        [TransactionScopeAspect()]
        //[PerformanceCounter()]
        public Product Add(Product product, Category category)
        {
            var addedCategory = _categoryDal.Add(category);
            product.CategoryId = addedCategory.CategoryId;

            var addedProduct = _productDal.Add(product);

            return addedProduct;
        }
        
        public List<ProductDetail> GetWithCategory()
        {
            return _productDal.GetWithCategory();
        }
       
        public List<Product> GetWithSp(int stok)
        {
            return _productDal.GetWithSp(stok);
        }
     
        //[SecuredOperation("Admin")]
        public void UpdateDate()
        {
            _productDal.UpdateDate();
        }
   
        public List<Product> UrunFiltrele(Product filtrelenecekUrun)
        {
            var filters = new List<SearchFilter>();

            if (!String.IsNullOrEmpty(filtrelenecekUrun.ProductName))
            {
                filters.Add(new SearchFilter
                {
                    Operation = Op.Contains,
                    PropertyName = "ProductName",
                    Value = filtrelenecekUrun.ProductName
                });
            }
            if (filtrelenecekUrun.CategoryId > 0)
            {
                filters.Add(new SearchFilter
                {
                    Operation = Op.Equals,
                    PropertyName = "CategoryId",
                    Value = filtrelenecekUrun.CategoryId
                });
            }
            if (filtrelenecekUrun.UnitPrice > 0)
            {
                filters.Add(new SearchFilter
                {
                    Operation = Op.GreaterThanOrEqual,
                    PropertyName = "UnitPrice",
                    Value = filtrelenecekUrun.UnitPrice
                });
            }
            var deleg = ExpressionBuilder.GetExpression<Product>(filters).Compile();

            return _productDal.Search(deleg);
        }
    }
}
